﻿using System;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace ObservableDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            IObservable<Ticket> ticketObservable = Observable.Create((Func<IObserver<Ticket>, IDisposable>)TicketFactory.TicketSubscribe);

            using (IDisposable handle = ticketObservable.Subscribe(ticket => Console.WriteLine(ticket.ToString())))
            {
                Console.WriteLine("\nPress ENTER to unsubscribe...\n");
                Console.ReadLine();
            }
           

            Console.WriteLine("Hello World!");
        }

        


    }

   





    public class A : IDisposable
    {
        private const int HiValueTryCount = 3;
        private const int Multiplier = 100;
       
        private readonly EventLoopScheduler _scheduler = new EventLoopScheduler();
        private int _hiValue;
        private bool _initialized;
        private int _loValue;


        public void Dispose()
        {

        }

        public async Task<long> GetNextId()
        {
            // Push the actual generation of the ID through the event loop scheduler to serialize things.
            // For what we're trying to demonstrate here we will be fine running everything on a single thread.
            return await Observable.Create<long>(async obs =>
            {
                if (!_initialized || _loValue >= Multiplier)
                {
                    _hiValue = await GetNextHiValue();
                    _loValue = 0;
                    _initialized = true;
                }

                _loValue++;

                obs.OnNext(_hiValue * Multiplier + _loValue);
                obs.OnCompleted();

                return Disposable.Empty;
            }).SubscribeOn(_scheduler);
        }

        private async Task<int> GetNextHiValue(int triesLeft = HiValueTryCount)
        {
            return 5;
        }
    }


    class Ticket
    {
        private readonly string ticketID;
        private readonly DateTime timeStamp;

        public Ticket(string tid)
        {
            ticketID = tid;
            timeStamp = DateTime.Now;
        }

        public override string ToString()
        {
            return String.Format("Ticket ID : {0}\nTimestamp : {1}\n", ticketID, timeStamp.ToString());
        }
    }
    public class TicketFactory : IDisposable
    {
        private bool bGenerate = true;


        internal TicketFactory(object ticketObserver)
        {
          
            Task.Factory.StartNew(new Action<object>(TicketGenerator), ticketObserver);
        }

        public void Dispose()
        {
            bGenerate = false;
        }
       
        private void TicketGenerator(object observer)
        {
            IObserver<Ticket> ticketObserver = (IObserver<Ticket>)observer;
            Ticket t;

            while (bGenerate)
            {
                t = new Ticket(Guid.NewGuid().ToString());
                ticketObserver.OnNext(t);
                Thread.Sleep(3000);
            }
        }

      
        public static IDisposable TicketSubscribe(object ticketObserver)
        {
            TicketFactory tf = new TicketFactory(ticketObserver);

            return tf;
        }
    }

}
